home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src.arc / IP.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  12KB  |  479 lines

  1. /* Upper half of IP, consisting of send/receive primitives, including
  2.  * fragment reassembly, for higher level protocols.
  3.  * Not needed when running as a standalone gateway.
  4.  */
  5. #include "global.h"
  6. #include "config.h"
  7. #include "mbuf.h"
  8. #include "timer.h"
  9. #include "internet.h"
  10. #include "iface.h"
  11. #include "ip.h"
  12. #include "icmp.h"
  13. #include "tcp.h"
  14. #include "udp.h"
  15.  
  16. #ifdef    TRACE
  17. extern struct iface Loopback;
  18. #endif
  19.  
  20. static struct mbuf *fraghandle __ARGS((struct ip *ip,struct mbuf *bp));
  21. static void ip_timeout __ARGS((void *arg));
  22. static void free_reasm __ARGS((struct reasm *rp));
  23. static void freefrag __ARGS((struct frag *fp));
  24. static struct reasm *lookup_reasm __ARGS((struct ip *ip));
  25. static struct reasm *creat_reasm __ARGS((struct ip *ip));
  26. static struct frag *newfrag __ARGS((int16 offset,int16 last,struct mbuf *bp));
  27.  
  28. int16 Ip_ttl = MAXTTL;    /* Default time-to-live for IP datagrams */
  29. int32 Ip_rtime = TLB;
  30. struct reasm *Reasmq;
  31. static struct raw_ip *Raw_ip;
  32.  
  33. #define    INSERT    0
  34. #define    APPEND    1
  35. #define    PREPEND    2
  36.  
  37. /* Send an IP datagram. Modeled after the example interface on p 32 of
  38.  * RFC 791
  39.  */
  40. int
  41. ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
  42. int32 source;            /* source address */
  43. int32 dest;            /* Destination address */
  44. char protocol;            /* Protocol */
  45. char tos;            /* Type of service */
  46. char ttl;            /* Time-to-live */
  47. struct mbuf *bp;        /* Data portion of datagram */
  48. int16 length;            /* Optional length of data portion */
  49. int16 id;            /* Optional identification */
  50. char df;            /* Don't-fragment flag */
  51. {
  52.     struct mbuf *tbp;
  53.     struct ip ip;        /* Pointer to IP header */
  54.     static int16 id_cntr;    /* Datagram serial number */
  55.     struct phdr *phdr;
  56.  
  57.     if(length == 0 && bp != NULLBUF)
  58.         length = len_mbuf(bp);
  59.     if(id == 0)
  60.         id = id_cntr++;        
  61.     if(ttl == 0)
  62.         ttl = Ip_ttl;
  63.  
  64.     /* Fill in IP header */
  65.     ip.tos = tos;
  66.     ip.length = IPLEN + length;
  67.     ip.id = id;
  68.     ip.offset = 0;
  69.     ip.flags.mf = 0;
  70.     ip.flags.df = df;
  71.     ip.ttl = ttl;
  72.     ip.protocol = protocol;
  73.     ip.source = source;
  74.     ip.dest = dest;
  75.     ip.optlen = 0;
  76.     if((tbp = htonip(&ip,bp)) == NULLBUF){
  77.         free_p(bp);
  78.         return -1;
  79.     }
  80.     if((bp = pushdown(tbp,sizeof(struct phdr))) == NULLBUF){
  81.         free_p(tbp);
  82.         return -1;
  83.     }
  84.     phdr = (struct phdr *)bp->data;
  85. #ifdef    TRACE
  86.     if(ip.dest == Ip_addr)
  87.         phdr->iface = &Loopback;
  88.     else
  89.         phdr->iface = NULLIF;
  90. #else
  91.     phdr->iface = NULLIF;
  92. #endif
  93.     phdr->type = TYPE_IP;    
  94.     enqueue(&Hopper,bp);
  95.     return 0;
  96. }
  97.  
  98. /* Reassemble incoming IP fragments and dispatch completed datagrams
  99.  * to the proper transport module
  100.  */
  101. void
  102. ip_recv(ip,bp,rxbroadcast)
  103. struct ip *ip;        /* Extracted IP header */
  104. struct mbuf *bp;    /* Data portion */
  105. char rxbroadcast;    /* True if received on subnet broadcast address */
  106. {
  107.     /* Function to call with completed datagram */
  108.     void (*recv) __ARGS((struct mbuf *bp,struct ip *ip,int rxbroadcast));
  109.     register struct raw_ip *rp;
  110.     struct mbuf *bp1,*tbp;
  111.     int rxcnt = 0;
  112.  
  113.     /* If we have a complete packet, call the next layer
  114.      * to handle the result. Note that fraghandle passes back
  115.      * a length field that does NOT include the IP header
  116.      */
  117.     if((bp = fraghandle(ip,bp)) == NULLBUF)
  118.         return;        /* Not done yet */
  119.  
  120.     for(rp = Raw_ip;rp != NULLRIP;rp = rp->next){
  121.         if(rp->protocol != ip->protocol)
  122.             continue;
  123.         rxcnt++;
  124.         /* Duplicate the data portion, and put the header back on */
  125.         dup_p(&bp1,bp,0,len_mbuf(bp));
  126.         if(bp1 != NULLBUF && (tbp = htonip(ip,bp1)) != NULLBUF){
  127.             enqueue(&rp->rcvq,tbp);
  128.             if(rp->r_upcall != NULLVFP)
  129.                 (*rp->r_upcall)(rp);
  130.         } else {
  131.             free_p(bp1);
  132.         }
  133.     }
  134.     /* Check for protocols we can't handle */
  135.     switch(uchar(ip->protocol)){
  136.     case TCP_PTCL:
  137.         recv = tcp_input;
  138.         break;
  139.     case UDP_PTCL:
  140.         recv = udp_input;
  141.         break;
  142.     case ICMP_PTCL:
  143.         recv = icmp_input;
  144.         break;
  145.     default:
  146.         recv = NULLVFP;
  147.         break;
  148.     }
  149.     if(recv != NULLVFP){
  150.         /* Pass the completed packet upstairs. The internal-format
  151.          * IP header is now passed here instead of the separated
  152.          * fields to make it easier for UDP to generate ICMP port
  153.          * unreachables. Poor layering in the architecture results
  154.          * in poor software modularity...
  155.          */
  156.         (*recv)(bp,ip,rxbroadcast);
  157.     } else {
  158.         if(rxcnt == 0){
  159.             /* Send an ICMP Protocol Unknown response... */
  160.             Ip_stats.badproto++;
  161.             /* ...unless it's a broadcast */
  162.             if(!rxbroadcast){
  163.                 icmp_output(ip,bp,DEST_UNREACH,PROT_UNREACH,(union icmp_args *)NULL);
  164.             }
  165.         }
  166.         free_p(bp);
  167.     }
  168. }
  169. /* Process IP datagram fragments
  170.  * If datagram is complete, return it with ip->length containing the data
  171.  * length (MINUS header); otherwise return NULLBUF
  172.  */
  173. static
  174. struct mbuf *
  175. fraghandle(ip,bp)
  176. struct ip *ip;        /* IP header, host byte order */
  177. struct mbuf *bp;    /* The fragment itself */
  178. {
  179.     register struct reasm *rp; /* Pointer to reassembly descriptor */
  180.     struct frag *lastfrag,*nextfrag,*tfp;
  181.     struct mbuf *tbp;
  182.     int16 i;
  183.     int16 last;        /* Index of first byte beyond fragment */
  184.  
  185.     last = ip->offset + ip->length - (IPLEN + ip->optlen);
  186.  
  187.     rp = lookup_reasm(ip);
  188.     if(ip->offset == 0 && !ip->flags.mf){
  189.         /* Complete datagram received. Discard any earlier fragments */
  190.         if(rp != NULLREASM)
  191.             free_reasm(rp);
  192.  
  193.         return bp;
  194.     }
  195.     if(rp == NULLREASM){
  196.         /* First fragment; create new reassembly descriptor */
  197.         if((rp = creat_reasm(ip)) == NULLREASM){
  198.             /* No space for descriptor, drop fragment */
  199.             free_p(bp);
  200.             return NULLBUF;
  201.         }
  202.     }
  203.     /* Keep restarting timer as long as we keep getting fragments */
  204.     stop_timer(&rp->timer);
  205.     start_timer(&rp->timer);
  206.  
  207.     /* If this is the last fragment, we now know how long the
  208.      * entire datagram is; record it
  209.      */
  210.     if(!ip->flags.mf)
  211.         rp->length = last;
  212.  
  213.     /* Set nextfrag to the first fragment which begins after us,
  214.      * and lastfrag to the last fragment which begins before us
  215.      */
  216.     lastfrag = NULLFRAG;
  217.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  218.         if(nextfrag->offset > ip->offset)
  219.             break;
  220.         lastfrag = nextfrag;
  221.     }
  222.     /* Check for overlap with preceeding fragment */
  223.     if(lastfrag != NULLFRAG  && ip->offset < lastfrag->last){
  224.         /* Strip overlap from new fragment */
  225.         i = lastfrag->last - ip->offset;
  226.         pullup(&bp,NULLCHAR,i);
  227.         if(bp == NULLBUF)
  228.             return NULLBUF;    /* Nothing left */
  229.         ip->offset += i;
  230.     }
  231.     /* Look for overlap with succeeding segments */
  232.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  233.         tfp = nextfrag->next;    /* save in case we delete fp */
  234.  
  235.         if(nextfrag->offset >= last)
  236.             break;    /* Past our end */
  237.         /* Trim the front of this entry; if nothing is
  238.          * left, remove it.
  239.          */
  240.         i = last - nextfrag->offset;
  241.         pullup(&nextfrag->buf,NULLCHAR,i);
  242.         if(nextfrag->buf == NULLBUF){
  243.             /* superseded; delete from list */
  244.             if(nextfrag->prev != NULLFRAG)
  245.                 nextfrag->prev->next = nextfrag->next;
  246.             else
  247.                 rp->fraglist = nextfrag->next;
  248.             if(tfp->next != NULLFRAG)
  249.                 nextfrag->next->prev = nextfrag->prev;
  250.             freefrag(nextfrag);
  251.         } else
  252.             nextfrag->offset = last;
  253.     }
  254.     /* Lastfrag now points, as before, to the fragment before us;
  255.      * nextfrag points at the next fragment. Check to see if we can
  256.      * join to either or both fragments.
  257.      */
  258.     i = INSERT;
  259.     if(lastfrag != NULLFRAG && lastfrag->last == ip->offset)
  260.         i |= APPEND;
  261.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  262.         i |= PREPEND;
  263.     switch(i){
  264.     case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  265.         tfp = newfrag(ip->offset,last,bp);
  266.         tfp->prev = lastfrag;
  267.         tfp->next = nextfrag;
  268.         if(lastfrag != NULLFRAG)
  269.             lastfrag->next = tfp;    /* Middle of list */
  270.         else
  271.             rp->fraglist = tfp;    /* First on list */
  272.         if(nextfrag != NULLFRAG)
  273.             nextfrag->prev = tfp;
  274.         break;
  275.     case APPEND:    /* Append to lastfrag */
  276.         append(&lastfrag->buf,bp);
  277.         lastfrag->last = last;    /* Extend forward */
  278.         break;
  279.     case PREPEND:    /* Prepend to nextfrag */
  280.         tbp = nextfrag->buf;
  281.         nextfrag->buf = bp;
  282.         append(&nextfrag->buf,tbp);
  283.         nextfrag->offset = ip->offset;    /* Extend backward */
  284.         break;
  285.     case (APPEND|PREPEND):
  286.         /* Consolidate by appending this fragment and nextfrag
  287.          * to lastfrag and removing the nextfrag descriptor
  288.          */
  289.         append(&lastfrag->buf,bp);
  290.         append(&lastfrag->buf,nextfrag->buf);
  291.         nextfrag->buf = NULLBUF;
  292.         lastfrag->last = nextfrag->last;
  293.  
  294.         /* Finally unlink and delete the now unneeded nextfrag */
  295.         lastfrag->next = nextfrag->next;
  296.         if(nextfrag->next != NULLFRAG)
  297.             nextfrag->next->prev = lastfrag;
  298.         freefrag(nextfrag);
  299.         break;
  300.     }
  301.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG 
  302.         && rp->length != 0){
  303.         /* We've gotten a complete datagram, so extract it from the
  304.          * reassembly buffer and pass it on.
  305.          */
  306.         bp = rp->fraglist->buf;
  307.         rp->fraglist->buf = NULLBUF;
  308.         /* Tell IP the entire length */
  309.         ip->length = rp->length + (IPLEN + ip->optlen);
  310.         free_reasm(rp);
  311.         return bp;
  312.     } else
  313.         return NULLBUF;
  314. }
  315. /* Arrange for receipt of raw IP datagrams */
  316. struct raw_ip *
  317. raw_ip(protocol,r_upcall)
  318. char protocol;
  319. void (*r_upcall)();
  320. {
  321.     register struct raw_ip *rp;
  322.  
  323.     rp = (struct raw_ip *)calloc(1,sizeof(struct raw_ip));
  324.     rp->protocol = protocol;
  325.     rp->r_upcall = r_upcall;
  326.     rp->next = Raw_ip;
  327.     if(rp->next != NULLRIP)
  328.         rp->next->prev = rp;
  329.     Raw_ip = rp;
  330.     return rp;
  331. }
  332. /* Free a raw IP descriptor */
  333. void
  334. del_ip(rpp)
  335. struct raw_ip *rpp;
  336. {
  337.     register struct raw_ip *rp;
  338.  
  339.     /* Do sanity check on arg */
  340.     for(rp = Raw_ip;rp != NULLRIP;rp = rp->next)
  341.         if(rp == rpp)
  342.             break;
  343.     if(rp == NULLRIP)
  344.         return;    /* Doesn't exist */
  345.  
  346.     /* Unlink */
  347.     if(rp->prev != NULLRIP)
  348.         rp->prev->next = rp->next;
  349.     else
  350.         Raw_ip = rp->next;
  351.     if(rp->next != NULLRIP)
  352.         rp->next->prev = rp->prev;
  353.     /* Free resources */
  354.     free_q(&rp->rcvq);
  355.     free((char *)rp);
  356. }
  357.  
  358. static struct reasm *
  359. lookup_reasm(ip)
  360. struct ip *ip;
  361. {
  362.     register struct reasm *rp;
  363.  
  364.     for(rp = Reasmq;rp != NULLREASM;rp = rp->next){
  365.         if(ip->source == rp->source && ip->dest == rp->dest
  366.          && ip->protocol == rp->protocol && ip->id == rp->id)
  367.             return rp;
  368.     }
  369.     return NULLREASM;
  370. }
  371. #ifdef    FOO
  372. static
  373. int16
  374. hash_reasm(source,dest,protocol,id)
  375. int32 source;
  376. int32 dest,
  377. char protocol;
  378. int16 id;
  379. {
  380.     register unsigned int hval;
  381.  
  382.     hval = loword(source);
  383.     hval ^= hiword(source);
  384.     hval ^= loword(dest);
  385.     hval ^= hiword(dest);
  386.     hval ^= uchar(protocol);
  387.     hval ^= id;
  388.     return hval % RHASH;
  389. }
  390. #endif
  391. /* Create a reassembly descriptor,
  392.  * put at head of reassembly list
  393.  */
  394. static struct reasm *
  395. creat_reasm(ip)
  396. register struct ip *ip;
  397. {
  398.     register struct reasm *rp;
  399.  
  400.     if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULLREASM)
  401.         return rp;    /* No space for descriptor */
  402.     rp->source = ip->source;
  403.     rp->dest = ip->dest;
  404.     rp->id = ip->id;
  405.     rp->protocol = ip->protocol;
  406.     rp->timer.start = Ip_rtime / MSPTICK;
  407.     rp->timer.func = ip_timeout;
  408.     rp->timer.arg = rp;
  409.  
  410.     rp->next = Reasmq;
  411.     if(rp->next != NULLREASM)
  412.         rp->next->prev = rp;
  413.     Reasmq = rp;
  414.     return rp;
  415. }
  416.  
  417. /* Free all resources associated with a reassembly descriptor */
  418. static void
  419. free_reasm(rp)
  420. register struct reasm *rp;
  421. {
  422.     register struct frag *fp;
  423.  
  424.     stop_timer(&rp->timer);
  425.     /* Remove from list of reassembly descriptors */
  426.     if(rp->prev != NULLREASM)
  427.         rp->prev->next = rp->next;
  428.     else
  429.         Reasmq = rp->next;
  430.     if(rp->next != NULLREASM)
  431.         rp->next->prev = rp->prev;
  432.     /* Free any fragments on list, starting at beginning */
  433.     while((fp = rp->fraglist) != NULLFRAG){
  434.         rp->fraglist = fp->next;
  435.         free_p(fp->buf);
  436.         free((char *)fp);
  437.     }
  438.     free((char *)rp);
  439. }
  440.  
  441. /* Handle reassembly timeouts by deleting all reassembly resources */
  442. static void
  443. ip_timeout(arg)
  444. void *arg;
  445. {
  446.     register struct reasm *rp;
  447.  
  448.     rp = (struct reasm *)arg;
  449.     free_reasm(rp);
  450. }
  451. /* Create a fragment */
  452. static
  453. struct frag *
  454. newfrag(offset,last,bp)
  455. int16 offset,last;
  456. struct mbuf *bp;
  457. {
  458.     struct frag *fp;
  459.  
  460.     if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULLFRAG){
  461.         /* Drop fragment */
  462.         free_p(bp);
  463.         return NULLFRAG;
  464.     }
  465.     fp->buf = bp;
  466.     fp->offset = offset;
  467.     fp->last = last;
  468.     return fp;
  469. }
  470. /* Delete a fragment, return next one on queue */
  471. static
  472. void
  473. freefrag(fp)
  474. struct frag *fp;
  475. {
  476.     free_p(fp->buf);
  477.     free((char *)fp);
  478. }
  479.